home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
SciAn
/
src
/
ScianTimers.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
60KB
|
2,652 lines
/*ScianTimers.c
Timers in scian
Eric Pepke
September 9, 1990
*/
#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianLists.h"
#include "ScianErrors.h"
#include "ScianWindows.h"
#include "ScianObjWindows.h"
#include "ScianIDs.h"
#include "ScianTimers.h"
#include "ScianScripts.h"
#include "ScianDialogs.h"
#include "ScianSliders.h"
#include "ScianSpaces.h"
#include "ScianDraw.h"
#include "ScianStyle.h"
#include "ScianColors.h"
#include "ScianTextBoxes.h"
#include "ScianMethods.h"
#include "ScianDepend.h"
#include "ScianPictures.h"
#include "ScianEvents.h"
#include "ScianControls.h"
#include "ScianDatasets.h"
#include "ScianFontSystem.h"
extern ObjPtr curSpace; /*The current space*/
ObjPtr timedObjClass; /*Time dependant object*/
ObjPtr timeControlClass; /*Class for time controls*/
double clockStarted = 0.0; /*Time at which clock was started*/
double clockStopped = 0.0; /*Time clock was stopped*/
double videoClock = 0.0; /*Video clock*/
Bool clockOn = true; /*True iff clock is on*/
long startTime; /*Starting time of machine*/
#define SCROLLTIME /*Autoscroll the time control*/
static real dummy = 1.0;
#define CEDGE 3
AlarmRec alarms[NALARMS]; /*The alarms*/
/*Internal prototypes*/
#ifdef PROTO
static int TimeToPixel(ObjPtr control, real time);
static real PixelToTime(ObjPtr, int);
#else
static int TimeToPixel();
static real PixelToTime();
#endif
/*States for time reader machine*/
#define TS_BEFORESIGN 1 /*Before plus or minus sign*/
#define TS_INWHOLE 2 /*Whole part*/
#define TS_INFRAC 3 /*Fractional part*/
#define TS_BEFOREEXP 4 /*Before pluse or minus exponent*/
#define TS_INEXP 6 /*In exponent*/
#define TS_DONE 7
void TinyDelay()
/*Does a tiny little delay*/
{
int k;
for (k = 0; k < 10; ++k)
dummy = dummy * dummy;
}
#ifdef PROTO
int ParseTime(real *t, int *f, char s[])
#else
int ParseTime(t, f, s)
real *t;
int *f;
char s[];
#endif
/*Parses a time in s. Puts the time format in f and the time in t.
Returns >0 if it worked. Returns <=0 if there was an error*/
{
double time;
int format;
double curNumber;
double sign = 1.0;
double fracDiv;
double expSign;
double curExp = 0.0;
int k;
int state = TS_BEFORESIGN;
format = 0;
time = 0.0;
curNumber = 0.0;
for (k = 0; s[k] && (state != TS_DONE); ++k)
{
if (!isspace(s[k]))
{
switch(state)
{
case TS_BEFORESIGN: /*Before number sign*/
if (s[k] == '-')
{
sign = -1.0;
break;
}
else if (s[k] == '+')
{
state = TS_INWHOLE;
break;
}
else
{
state = TS_INWHOLE;
/*Fall through*/
}
case TS_INWHOLE: /*In the whole part of the number*/
format |= TF_SECONDS;
if (s[k] == ':')
{
/*Next is minutes or seconds. Save and continue*/
format |= format << 1;
time += curNumber;
time *= 60.0;
curNumber = 0.0;
}
else if (s[k] >= '0' && s[k] <= '9')
{
curNumber *= 10.0;
curNumber += s[k] - '0';
}
else if (s[k] == '.')
{
fracDiv = 1.0;
state = TS_INFRAC;
format |= TF_SUBSECONDS;
}
else if (s[k] == 'E' || s[k] == 'e' ||
s[k] == 'F' || s[k] == 'f' ||
s[k] == 'G' || s[k] == 'g')
{
expSign = 1.0;
curExp = 0.0;
state = TS_BEFOREEXP;
}
else
{
/*Error*/
return -k;
}
break;
case TS_INFRAC: /*In the fractional part*/
format |= TF_SUBSECONDS;
if (s[k] >= '0' && s[k] <= '9')
{
fracDiv *= 0.1;
curNumber += fracDiv * (double) (s[k] - '0');
}
else if (s[k] == 'E' || s[k] == 'e' ||
s[k] == 'F' || s[k] == 'f' ||
s[k] == 'G' || s[k] == 'g')
{
expSign = 1.0;
curExp = 0.0;
state = TS_BEFOREEXP;
}
else
{
/*Error*/
return -k;
}
break;
case TS_BEFOREEXP:
format |= TF_SUBSECONDS;
if (s[k] == '-')
{
expSign = -1.0;
format = TS_INEXP;
break;
}
else if (s[k] == '+')
{
format = TS_INEXP;
break;
}
/*Fall through*/
case TS_INEXP:
if (s[k] >= '0' && s[k] <= '9')
{
curExp *= 10.0;
curExp += (double) (s[k] - '0');
}
else return -k;
}
}
}
/*Finish up filling in the time*/
if (curExp != 0.0)
{
curNumber *= pow(10.0, curExp * expSign);
curExp = 0.0;
}
time += curNumber * sign;
*t = time;
*f = format;
return k;
}
ObjPtr NewTimedObject(timeSteps, timeData)
ObjPtr timeSteps, timeData;
/*Returns a new timed object made up of timeSteps and timeData pointing to
repObj*/
{
ObjPtr timedObj, stepsArray, dataArray;
real *stepElements;
ObjPtr *dataElements;
ThingListPtr stepsRunner, dataRunner;
long nSteps, k;
nSteps = ListCount(timeSteps);
stepsArray = NewArray(AT_REAL, 1, &nSteps);
dataArray = NewArray(AT_OBJECT, 1, &nSteps);
if (!stepsArray || !dataArray)
{
return NULLOBJ;
}
stepsRunner = LISTOF(timeSteps);
dataRunner = LISTOF(timeData);
stepElements = ELEMENTS(stepsArray);
dataElements = ELEMENTS(dataArray);
k = 0;
while (stepsRunner)
{
if (!dataRunner)
{
ReportError("NewTimedObject", "Not enough data for timesteps");
}
else
{
stepElements[k] = GetReal(stepsRunner -> thing);
dataElements[k] = dataRunner -> thing;
}
stepsRunner = stepsRunner -> next;
dataRunner = dataRunner -> next;
++k;
}
timedObj = NewObject(timedObjClass, 0);
SetVar(timedObj, TIMESTEPS, stepsArray);
SetVar(timedObj, TIMEDATA, dataArray);
return timedObj;
}
ObjPtr MakeTimeBounds(timedObj)
ObjPtr timedObj;
/*Calculates the time bounds of a timedObj*/
{
ObjPtr timeSteps; /*Array of time steps*/
real *timeElements;
real tb[2];
ObjPtr timeBounds;
MakeVar(timedObj, TIMESTEPS);
timeSteps = GetVar(timedObj, TIMESTEPS);
if (!timeSteps)
{
return ObjFalse;
}
timeElements = ELEMENTS(timeSteps);
/*New method of doing time step*/
if (DIMS(timeSteps)[0] == 1)
{
tb[0] = tb[1] = timeElements[0];
}
else
{
tb[0] = timeElements[0] +
0.5 * (timeElements[0] - timeElements[1]);
tb[1] = timeElements[DIMS(timeSteps)[0] - 1] +
0.5 * ( timeElements[DIMS(timeSteps)[0] - 1] -
timeElements[DIMS(timeSteps)[0] - 2]);
}
timeBounds = NewRealArray(1, 2L);
CArray2Array(timeBounds, tb);
SetVar(timedObj, TIMEBOUNDS, timeBounds);
return ObjTrue;
}
Bool InsertTimeSlice(timedObj, time, data)
ObjPtr timedObj, time, data;
/*Inserts a time slice of data at time into timedObj*/
{
ObjPtr timeSteps, timeData;
long index;
real *elements;
real curTime;
MakeVar(timedObj, TIMESTEPS);
timeSteps = GetArrayVar("InsertTimeSlice", timedObj, TIMESTEPS);
timeData = GetVar(timedObj, TIMEDATA);
if (!timeSteps || !timeData)
{
return false;
}
curTime = GetReal(time);
index = SearchReal(timeSteps, curTime);
if (index < 0)
{
return false;
}
/*See if this is a duplication of an existing time step*/
elements = ELEMENTS(timeSteps);
if (index < DIMS(timeSteps)[0] && elements[index] == curTime)
{
/*DIKEO change to replace the time step later*/
return true;
}
if (index - 1 >= 0 && elements[index - 1] == curTime)
{
return true;
}
timeSteps = InsertInArray(timeSteps, time, index);
timeData = InsertInArray(timeData, data, index);
SetVar(timedObj, TIMESTEPS, timeSteps);
SetVar(timedObj, TIMEDATA, timeData);
if (index == 0 || index >= DIMS(timeSteps)[0])
{
MakeVar(timedObj, TIMEBOUNDS);
}
return true;
}
double WallClock()
/*Returns the wall clock time*/
{
struct tms buffer;
return ((double) (times(&buffer) - startTime)) / HEARTBEAT - clockStarted;
}
double Clock()
/*Returns the clock. This differs between real-time and single-frame.*/
{
if (runningScript)
{
return videoClock - clockStarted;
}
else
{
return WallClock();
}
}
void SetSystemClock(time)
double time;
/*Sets the system clock to time*/
{
struct tms buffer;
double supposedTime;
if (runningScript)
{
supposedTime = videoClock;
}
else
{
supposedTime = ((double) (times(&buffer) - startTime)) / HEARTBEAT;
}
clockStarted = time - supposedTime;
}
void ClockOff()
/*Turns the clock off for a moment*/
{
struct tms buffer;
if (clockOn)
{
clockOn = false;
if (runningScript)
{
clockStopped = videoClock;
}
else
{
clockStopped = ((double) (times(&buffer) - startTime)) / HEARTBEAT;
}
}
}
void ClockOn()
/*Turns the clock back on*/
{
struct tms buffer;
if (!clockOn)
{
clockOn = true;
if (runningScript)
{
clockStarted += videoClock - clockStopped;
}
else
{
clockStarted += ((double) (times(&buffer) - startTime)) / HEARTBEAT - clockStopped;
}
}
}
ObjPtr RegisterTimedField(timedObj, whichField)
ObjPtr timedObj;
int whichField;
/*Registers a timed object*/
{
FuncTyp method;
ObjPtr time;
ObjPtr floor, ceiling;
Bool interpolateP;
ObjPtr timeSteps, timeData; /*Time steps and data*/
long index;
real *elements;
real diffFloor, diffCeiling;
/*See if we need to interpolate*/
MakeVar(timedObj, INTERPOLATEP);
interpolateP = GetPredicate(timedObj, INTERPOLATEP);
/*Get the time steps*/
MakeVar(timedObj, TIMESTEPS);
timeSteps = GetArrayVar("FindFloorTimestep", timedObj, TIMESTEPS);
/*Get the timedata*/
MakeVar(timedObj, TIMEDATA);
timeData = GetVar(timedObj, TIMEDATA);
if (!timeSteps || !timeData)
{
ReportError("RegisterTimedField", "No timesteps or data");
return ObjFalse;
}
/*Find the closest upper bound time step*/
index = SearchReal(timeSteps, spaceTime);
if (index < 0)
{
ceiling = NULLOBJ;
}
else if (index >= DIMS(timeSteps)[0])
{
ceiling = NULLOBJ;
}
else
{
ceiling = GetObjectElement(timeData, &index);
}
--index;
if (index < 0)
{
floor = NULLOBJ;
}
else if (index >= DIMS(timeSteps)[0])
{
floor = NULLOBJ;
}
else
{
floor = GetObjectElement(timeData, &index);
}
if (!floor && !ceiling)
{
/*Neither floor nor ceiling, error and return*/
ReportError("RegisterTimedField", "No floor or ceiling");
return ObjFalse;
}
if (!floor)
{
/*No floor, must use ceiling*/
method = GetMethodSurely("RegisterTimedField", ceiling, REGISTERFIELD);
if (method)
{
ObjPtr result;
result = (*method)(ceiling, whichField);
return result;
}
}
else if (!ceiling)
{
/*No ceiling, must use floor*/
method = GetMethodSurely("RegisterTimedField", floor, REGISTERFIELD);
if (method)
{
ObjPtr result;
result = (*method)(floor, whichField);
return result;
}
}
else
{
elements = ELEMENTS(timeSteps);
if (interpolateP)
{
/*Set up to interpolate later by setting the two timesteps*/
diffFloor = ABS(elements[index] - spaceTime);
diffCeiling = ABS(elements[index + 1] - spaceTime);
method = GetMethodSurely("RegisterTimedField", floor, REGISTERFIELD);
if (method)
{
ObjPtr result;
result = (*method)(floor, whichField);
}
curFields[whichField] . weight = diffCeiling / (diffFloor + diffCeiling);
curFields[whichField] . groupInterp = true;
method = GetMethodSurely("RegisterTimedField", ceiling, REGISTERFIELD);
if (method)
{
ObjPtr result;
result = (*method)(ceiling, whichField + MAXNCURFIELDS);
}
curFields[whichField + MAXNCURFIELDS] . weight = diffFloor / (diffFloor + diffCeiling);
curFields[whichField + MAXNCURFIELDS] . groupInterp = true;
return ObjTrue;
}
else
{
/*No interpolation, just use closest time step*/
ObjPtr closest;
diffFloor = ABS(elements[index] - spaceTime);
diffCeiling = ABS(elements[index + 1] - spaceTime);
if (diffFloor <= diffCeiling)
{
closest = floor;
}
else
{
closest = ceiling;
}
method = GetMethodSurely("RegisterTimedField", closest, REGISTERFIELD);
if (method)
{
ObjPtr result;
result = (*method)(closest, whichField);
return result;
}
}
}
return NULLOBJ;
}
#if 0
ObjPtr MakeTimedCurData(timedObj)
ObjPtr timedObj;
/*Makes a timed object's timeData*/
{
ObjPtr timeSteps, timeData; /*Time steps and data*/
ObjPtr retVal; /*Value to return*/
ObjPtr timeBounds; /*Time bounds of the current space*/
ObjPtr time; /*Current spaceTime*/
ObjPtr curObjTime; /*Current time for the object*/
ObjPtr interp1, interp2; /*Two arrays to interpolate between*/
real time1, time2; /*Times to interpolate*/
long index;
ObjPtr element; /*Elements of the array*/
Bool interpolateP;
MakeVar(timedObj, TIMEBOUNDS);
timeBounds = GetVar(timedObj, TIMEBOUNDS);
MakeVar(timedObj, INTERPOLATEP);
interpolateP = GetPredicate(timedObj, INTERPOLATEP);
if ((curObjTime = GetVar(timedObj, LASTTIME)) &&
(GetReal(curObjTime) == spaceTime) &&
(interpolateP == GetPredicate(timedObj, LASTINTERP)))
{
retVal = GetVar(timedObj, CURDATA);
SetVar(timedObj, CURDATA, retVal);
return ObjTrue;
}
SetVar(timedObj, LASTINTERP, interpolateP ? ObjTrue : ObjFalse);
MakeVar(timedObj, TIMESTEPS);
timeSteps = GetArrayVar("MakeTimedCurData", timedObj, TIMESTEPS);
timeData = GetVar(timedObj, TIMEDATA);
if (!timeSteps || !timeData)
{
ReportError("MakeTimedCurData", "No timesteps or data");
return ObjFalse;
}
/*Find the closest lower bound time step*/
index = SearchReal(timeSteps, spaceTime);
if (index <= 0)
{
retVal = GetObjectElement(timeData, &index);
}
else if (index >= DIMS(timeSteps)[0])
{
--index;
retVal = GetObjectElement(timeData, &index);
++index;
}
else
{
/*There's something to choose from or interpolate*/
real weight;
--index;
interp1 = GetObjectElement(timeData, &index);
++index;
interp2 = GetObjectElement(timeData, &index);
time1 = ((real *) ELEMENTS(timeSteps))[index - 1];
time2 = ((real *) ELEMENTS(timeSteps))[index];
weight = (spaceTime - time1) / (time2 - time1);
if (interpolateP && IsRealArray(((ObjPtr *) ELEMENTS(timeData))[index - 1]))
{
retVal = InterpArray(interp1, interp2, weight);
}
else if (weight > 0.5)
{
retVal = ((ObjPtr *) ELEMENTS(timeData))[index];
}
else
{
retVal = ((ObjPtr *) ELEMENTS(timeData))[index - 1];
}
}
SetVar(timedObj, CURDATA, retVal);
SetVar(timedObj, LASTTIME, NewReal(spaceTime));
return retVal;
}
#endif
Bool WakeMe(object, method, time)
ObjPtr object;
NameTyp method;
double time;
/*Puts in a request to wake an object by sending it a method at a certain
time. Returns true iff succeeds. The method will be passed a double
giving the lateness of the wakeup call*/
{
int k;
for (k = 0; k < NALARMS; ++k)
{
if (alarms[k] . object == NULLOBJ)
{
alarms[k] . object = object;
alarms[k] . method = method;
alarms[k] . when = time;
alarms[k] . wallTime = false;
alarms[k] . startTime = Clock();
AddToReferenceList(object);
return true;
}
}
return false;
}
Bool SetTimeout(object, method, time)
ObjPtr object;
NameTyp method;
double time;
/*Puts in a request to wake an object by sending it a method at a certain
time. Returns true iff succeeds. The method will be passed a double
giving the lateness of the wakeup call*/
{
int k;
for (k = 0; k < NALARMS; ++k)
{
if (alarms[k] . object == NULLOBJ)
{
alarms[k] . object = object;
alarms[k] . method = method;
alarms[k] . when = time;
alarms[k] . wallTime = true;
alarms[k] . startTime = WallClock();
AddToReferenceList(object);
return true;
}
}
return false;
}
void DoNotDisturb(object, method)
ObjPtr object;
NameTyp method;
/*Removes all wakeup calls for object and method*/
{
int k;
for (k = 0; k < NALARMS; ++k)
{
if (alarms[k] . object == object &&
alarms[k] . method == method)
{
ObjPtr object;
object = alarms[k] . object;
alarms[k] . object = 0;
DeleteThing(object);
}
}
}
void IdleTimers()
/*Idles all the timer stuff*/
{
int k;
for (k = 0; k < NALARMS; ++k)
{
double time;
if (alarms[k] . wallTime)
{
time = WallClock();
}
else
{
time = Clock();
}
if (alarms[k] . object && time >= alarms[k] . when)
{
ObjPtr object;
FuncTyp method;
object = alarms[k] . object;
alarms[k] . object = 0;
method = GetMethod(object, alarms[k] . method);
if (method)
{
(*method)(object, time - alarms[k] . startTime);
}
DeleteThing(object);
}
}
}
#ifdef PROTO
static int TimeToPixel(ObjPtr control, real time)
#else
static int TimeToPixel(control, time)
ObjPtr control;
real time;
#endif
/*Returns the x pixel for a specific time in a time control.
Check this against bounds of thing before drawing*/
{
ObjPtr var, scrollbar;
real value, tpp;
int l, r, b, t, mid;
Get2DIntBounds(control, &l, &r, &b, &t);
l += TCDSWIDTH + 2 * TCGAP + BARWIDTH;
mid = (l + r) / 2;
scrollbar = GetVar(control, HSCROLL);
if (scrollbar)
{
var = GetValue(scrollbar);
if (var)
{
value = GetReal(var);
}
else
{
value = 0.0;
}
}
else
{
value = 0.0;
}
var = GetVar(control, TIMEPERPIXEL);
if (var)
{
tpp = GetReal(var);
}
else
{
return mid;
}
return (time - value) / tpp + 0.5 + mid;
}
static real PixelToTime(control, pixel)
ObjPtr control;
int pixel;
/*Returns the time for a specific x pixel in a time control.
Check this against bounds of thing before drawing*/
{
ObjPtr var, scrollbar;
real value, tpp;
int l, r, b, t, mid;
Get2DIntBounds(control, &l, &r, &b, &t);
l += TCDSWIDTH + 2 * TCGAP + BARWIDTH;
mid = (l + r) / 2;
scrollbar = GetVar(control, HSCROLL);
if (scrollbar)
{
var = GetValue(scrollbar);
if (var)
{
value = GetReal(var);
}
else
{
value = 0.0;
}
}
else
{
value = 0.0;
}
var = GetVar(control, TIMEPERPIXEL);
if (var)
{
tpp = GetReal(var);
}
else
{
return value;
}
return (pixel - mid) * tpp + value;
}
#ifdef PROTO
void PrintTime(char *s, real t, int f)
#else
void PrintTime(s, t, f)
char *s;
real t;
int f;
#endif
/*Prints time t using predefined format f into string s*/
{
long hours;
long minutes;
long seconds;
if (f & TF_HOURS)
{
hours = t / 3600;
sprintf(s, "%d:", hours);
while (*s) ++s;
minutes = t / 60;
sprintf(s, "%02d", minutes - hours * 60);
while (*s) ++s;
if (f & TF_SECONDS)
{
seconds = t;
if (f & TF_SUBSECONDS)
{
sprintf(s, ":%02g", t - minutes * 60);
}
else
{
sprintf(s, ":%02d", seconds - minutes * 60);
}
}
}
else if (f & TF_MINUTES)
{
minutes = t / 60;
sprintf(s, "%d:", minutes);
while (*s) ++s;
seconds = t;
if (f & TF_SUBSECONDS)
{
sprintf(s, "%02g", t - minutes * 60);
}
else
{
sprintf(s, "%02d", seconds - minutes * 60);
}
}
else
{
sprintf(s, "%g", t);
}
}
void UpdateTimeReadout(control)
ObjPtr control;
/*Updates a time readout in a control*/
{
ObjPtr readout, clock, format, var;
char timeStr[256];
FuncTyp method;
readout = GetObjectVar("UpdateTimeReadout", control, READOUT);
if (!readout)
{
return;
}
clock = GetObjectVar("UpdateTimeReadout", control, REPOBJ);
if (!clock)
{
return;
}
var = GetVar(control, VALUE);
if (var)
{
MakeVar(control, TIMEFORMAT);
format = GetVar(control, TIMEFORMAT);
if (format)
{
PrintTime(timeStr, GetReal(var), GetInt(format));
}
else
{
sprintf(timeStr, "%g", GetReal(var));
}
}
else
{
strcpy(timeStr, "");
}
InhibitLogging(true);
method = GetMethod(readout, CHANGEDVALUE);
SetMethod(readout, CHANGEDVALUE, (FuncTyp) 0);
SetTextBox(readout, timeStr);
SetMethod(readout, CHANGEDVALUE, method);
InhibitLogging(false);
}
ObjPtr DrawTimeControl(object)
ObjPtr object;
/*Draws a time control*/
{
#ifdef GRAPHICS
ObjPtr hScroll, vScroll, readout, var, timeVar;
int left, right, bottom, top, timePix;
real value;
real downOffset;
ObjPtr datasets;
Bool madeDatasets;
ObjPtr clock;
long line;
Get2DIntBounds(object, &left, &right, &bottom, &top);
SetUIFont(TCFONT);
if (MakeVar(object, DATASETS))
{
RecalcScroll(object);
}
MakeVar(object, TIMESTEPS);
/*Get the clock*/
clock = GetObjectVar("DrawTimeControl", object, REPOBJ);
if (!clock)
{
return NULLOBJ;
}
/*Get current time*/
timeVar = GetVar(object, VALUE);
if (timeVar)
{
value = GetReal(timeVar);
}
else
{
value = 0.0;
}
/*Draw the scroll bars*/
hScroll = GetVar(object, HSCROLL);
if (hScroll)
{
DrawObject(hScroll);
}
vScroll = GetVar(object, VSCROLL);
if (vScroll)
{
DrawObject(vScroll);
}
/*Draw the readout*/
readout = GetVar(object, READOUT);
if (readout)
{
DrawObject(readout);
}
datasets = GetVar(object, DATASETS);
/*Draw the datasets box*/
FillUIRect(left + 1, left + TCDSWIDTH - 1, bottom + TCGAP + BARWIDTH + 1, top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP - 1, UIGRAY62);
/*Draw the contents of the datasets box*/
if (vScroll && datasets)
{
downOffset = GetReal(GetValue(vScroll));
line = (-downOffset / TCCELLHEIGHT);
if (line < DIMS(datasets)[0])
{
/*It's worth printing*/
int texty;
ObjPtr element;
SetClipRect(left + 1,
left + TCDSWIDTH - 1,
bottom + TCGAP + BARWIDTH + 1,
top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP - 1);
texty = top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP - 1 - (line + 1) * TCCELLHEIGHT + TCTEXTBOFF - downOffset;
SetUIColor(UIBLACK);
while (line < DIMS(datasets)[0] &&
texty > bottom + TCGAP + BARWIDTH + 1 - TCCELLHEIGHT)
{
ObjPtr name;
element = GetObjectElement(datasets, &line);
name = GetVar(element, NAME);
if (name)
{
DrawAString(LEFTALIGN, left + 1 + TCTEXTLOFF,
texty,
GetString(name));
}
else
{
DrawAString(LEFTALIGN, left + 1 + TCTEXTLOFF,
texty,
"?");
}
texty -= TCCELLHEIGHT;
++line;
}
RestoreClipRect();
}
}
/*Draw the frame of the datasets box*/
FrameUIRect(left, left + TCDSWIDTH, bottom + TCGAP + BARWIDTH, top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP, UIBLACK);
/*Draw the timeline box*/
FillUIRect( left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
bottom + TCGAP + BARWIDTH + 1,
top - 1,
UIGRAY62);
/*Draw the contents of the timeline box*/
if (vScroll && datasets)
{
ObjPtr var;
char timeStr[256];
int format;
MakeVar(object, TIMEFORMAT);
var = GetVar(object, TIMEFORMAT);
if (var)
{
format = GetInt(var);
}
else
{
format = TF_SECONDS + TF_SUBSECONDS;
}
/*Draw the time numbers*/
var = GetVar(object, TIMEPERPIXEL);
if (var)
{
/*It's valid; draw a whole range of times*/
real timePerPixel, timeAtPixel;
real displayStep;
int displayTics;
long tempLong;
int curPixel;
int timePixel;
real curTime;
int k;
timePerPixel = GetReal(var);
/*Get a pixel that's way off the left*/
timePixel = left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1 - TCMAXTIMEWIDTH;
timeAtPixel = PixelToTime(object, timePixel);
/*Get the step and tics*/
var = GetRealVar("DrawTimeControl", object, DISPLAYSTEP);
if (var)
{
displayStep = GetReal(var);
}
else
{
displayStep = 1.0;
}
var = GetIntVar("DrawTimeControl", object, DISPLAYTICS);
if (var)
{
displayTics = GetInt(var);
}
else
{
displayTics = 10;
}
/*Do the truncate bit*/
tempLong = timeAtPixel / displayStep;
timeAtPixel = tempLong * displayStep;
timePixel = TimeToPixel(object, timeAtPixel);
/*Write out the times*/
SetClipRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
top - TCTIMEHEIGHT + 1,
top - 1);
curPixel = timePixel;
curTime = timeAtPixel;
SetUIFont(TCTIMEFONT);
SetUIColor(UIBLACK);
do
{
if (format)
{
PrintTime(timeStr, curTime, format);
}
else
{
sprintf(timeStr, "%g", curTime);
}
DrawAString(CENTERALIGN, curPixel,
top - TCTIMEHEIGHT + 1 + TCTIMEBOFF,
timeStr);
curTime += displayStep;
tempLong = curTime / displayStep + 0.5;
curTime = tempLong * displayStep;
curPixel = TimeToPixel(object, curTime);
}
while (curPixel < right + TCMAXTIMEWIDTH);
/*Write out upper tic marks*/
curPixel = timePixel;
curTime = timeAtPixel;
k = 0;
SetUIColor(UIBLACK);
do
{
DrawUILine(curPixel, top - TCTIMEHEIGHT + (k % displayTics ? TCTIMEBOFF / 2 : TCTIMEBOFF) - 1,
curPixel, top - TCTIMEHEIGHT + 1,
UIGRAY25);
++k;
curTime += displayStep / displayTics;
curPixel = TimeToPixel(object, curTime);
}
while (curPixel < right + TCMAXTIMEWIDTH);
RestoreClipRect();
/*Write out lower tic marks*/
SetClipRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
bottom + BARWIDTH + TCGAP + 1,
top - TCTIMEHEIGHT - TCCURHEIGHT - TCGAP - 1);
curPixel = timePixel;
curTime = timeAtPixel;
do
{
DrawUILine(curPixel, top - TCTIMEHEIGHT - TCCURHEIGHT - TCGAP - 1,
curPixel, bottom + BARWIDTH + TCGAP + 1,
UIGRAY25);
curTime += displayStep;
curPixel = TimeToPixel(object, curTime);
}
while (curPixel < right + TCMAXTIMEWIDTH);
RestoreClipRect();
}
else if (timeVar)
{
/*Just draw a single time at the current time slider*/
real curTime;
int timePixel;
curTime = value;
timePixel = TimeToPixel(object, curTime);
/*Write out the time*/
SetClipRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
top - TCTIMEHEIGHT + 1,
top - 1);
SetUIFont(TCTIMEFONT);
SetUIColor(UIBLACK);
if (format)
{
PrintTime(timeStr, curTime, format);
}
else
{
sprintf(timeStr, "%g", curTime);
}
DrawAString(CENTERALIGN, timePixel,
top - TCTIMEHEIGHT + 1 + TCTIMEBOFF,
timeStr);
RestoreClipRect();
}
/*Draw the time lines*/
downOffset = GetReal(GetValue(vScroll));
line = (-downOffset / TCCELLHEIGHT);
if (line < DIMS(datasets)[0])
{
/*It's worth printing*/
int midy;
ObjPtr element;
SetClipRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
bottom + TCGAP + BARWIDTH + 1,
top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP - 1);
midy = top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP - 1 - (line + 1) * TCCELLHEIGHT + TCLINEBOFF - downOffset;
SetUIColor(UIBLACK);
while (line < DIMS(datasets)[0] &&
midy > bottom + TCGAP + BARWIDTH + 1 - TCCELLHEIGHT)
{
/*Print out the timeline of the object*/
Bool interpolateP;
ObjPtr timeSteps;
element = GetObjectElement(datasets, &line);
MakeVar(element, TIMESTEPS);
timeSteps = GetVar(element, TIMESTEPS);
MakeVar(element, INTERPOLATEP);
interpolateP = GetPredicate(element, INTERPOLATEP);
if (timeSteps)
{
/*Object with time steps. Find the first*/
int pixel;
long ts1, ts2;
real leftTime, rightTime;
/*Get a pixel that's clear off the left side*/
pixel = left;
leftTime = PixelToTime(object, pixel);
/*Get its index*/
ts1 = SearchReal(timeSteps, leftTime);
if (ts1 > 0)
{
--ts1;
}
{
/*There's a chance it can be drawn. Get a pixel
clear off the right*/
pixel = right + TCSAMPLESIZE;
rightTime = PixelToTime(object, pixel);
/*Get its index*/
ts2 = SearchReal(timeSteps, rightTime);
if (ts2 >= DIMS(timeSteps)[0])
{
--ts2;
}
if (ts2 >= ts1)
{
/*DrawIt*/
real *timeElements;
long k;
long coords[2];
int p1, p2;
timeElements = (real *) ELEMENTS(timeSteps);
element = GetObjectElement(datasets, &line);
p1 = TimeToPixel(object, timeElements[ts1]);
for (k = ts1 + 1; k <= ts2; ++k)
{
p2 = TimeToPixel(object, timeElements[k]);
if (!interpolateP)
{
DrawUILine((p1 + p2) / 2, midy + TCMIDTICHEIGHT,
(p1 + p2) / 2, midy - TCMIDTICHEIGHT - 1,
UIBLACK);
DrawUILine((p1 + p2) / 2 + 1, midy + TCMIDTICHEIGHT,
(p1 + p2) / 2 + 1, midy - TCMIDTICHEIGHT - 1,
UIBLACK);
setlinestyle(DASHEDLINE);
}
DrawUILine(p1, midy,
p2, midy,
UIBLACK);
DrawUILine(p1, midy - 1,
p2, midy - 1,
UIBLACK);
if (!interpolateP)
{
setlinestyle(SOLIDLINE);
}
p1 = p2;
}
for (k = ts1; k <= ts2; ++k)
{
pixel = TimeToPixel(object, timeElements[k]);
SetUIColor(TCSAMPLECOLOR);
FillRealQuad((real) pixel, (real) midy + TCSAMPLESIZE / 2,
(real) pixel - TCSAMPLESIZE / 2, (real) midy,
(real) pixel, (real) midy - TCSAMPLESIZE / 2,
(real) pixel + TCSAMPLESIZE / 2, (real) midy);
}
}
}
}
else
{
/*Eternal object*/
SetLineWidth(2);
DrawUILine(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1, midy,
right - 1, midy, TCSAMPLECOLOR);
SetLineWidth(1);
}
midy -= TCCELLHEIGHT;
++line;
}
RestoreClipRect();
}
}
FrameUIRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH,
right,
bottom + TCGAP + BARWIDTH,
top, UIBLACK);
DrawUILine( left + TCDSWIDTH + 2 * TCGAP + BARWIDTH,
top - TCTIMEHEIGHT,
right, top - TCTIMEHEIGHT,
UIBLACK);
DrawUILine( left + TCDSWIDTH + 2 * TCGAP + BARWIDTH,
top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP,
right,
top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP,
UIBLACK);
DrawUILine( left + TCDSWIDTH + 2 * TCGAP + BARWIDTH,
top - TCCURHEIGHT - TCTIMEHEIGHT - 1,
right,
top - TCCURHEIGHT - TCTIMEHEIGHT - 1,
UIBLACK);
FillUIRect( left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
top - TCTIMEHEIGHT - CEDGE,
top - TCTIMEHEIGHT,
UIBOTTOMEDGE);
FillUIRect( left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
top - TCTIMEHEIGHT - TCCURHEIGHT + CEDGE + 1,
top - TCTIMEHEIGHT - CEDGE - 1,
timeVar ? UIPGREEN : UIGRAY50);
FillUIRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
top - TCTIMEHEIGHT - TCCURHEIGHT,
top - TCTIMEHEIGHT - TCCURHEIGHT + CEDGE,
UITOPEDGE);
if (timeVar == NULLOBJ)
{
FillUIGauzeRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1,
right - 1,
top - TCTIMEHEIGHT - TCCURHEIGHT,
top - TCTIMEHEIGHT,
UIBACKGROUND);
}
if (timeVar)
{
timePix = TimeToPixel(object, value);
if (timePix > left + TCDSWIDTH + 2 * TCGAP + BARWIDTH - TCCURWIDTH &&
timePix < right + TCCURWIDTH)
{
/*Draw the time cursor*/
SetClipRect(left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1, right - 1, bottom + TCGAP + BARWIDTH + 1, top - 1);
DrawVCursor(timePix, top - 1 - TCTIMEHEIGHT + TCTIMEBOFF, bottom + TCGAP + BARWIDTH + 1);
DrawRaisedRect(timePix - TCCURWIDTH / 2, timePix + TCCURWIDTH / 2,
top - TCTIMEHEIGHT - TCCURHEIGHT + 1 + CEDGE, top - TCTIMEHEIGHT - 1 - CEDGE,
GetPredicate(object, HIGHLIGHTED) ? UIHIBACKGROUND : UIBACKGROUND);
RestoreClipRect();
}
}
/*Draw "Current time:"*/
SetUIColor(UIBLACK);
SetUIFont(TCFONT);
DrawAString(LEFTALIGN, left, top - TCTIMEHEIGHT + 1 + TCTIMEBOFF, "Current time:");
#endif
return ObjTrue;
}
static ObjPtr AutoScrollTimeControl(control)
ObjPtr control;
/*Auto scrolls a time control*/
{
ObjPtr var;
var = GetVar(control, VALUE);
if (var)
{
int left, right, bottom, top, timePix;
ObjPtr slider;
real value, testVal, midVal, lo, hi;
value = GetReal(var);
Get2DIntBounds(control, &left, &right, &bottom, &top);
slider = GetObjectVar("AutoScrollTimeControl", control, HSCROLL);
if (!slider)
{
return ObjFalse;
}
GetSliderRange(slider, &lo, &hi);
testVal = PixelToTime(control, left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1 + TCSCROLLBORDER);
if (value < testVal)
{
/*It's off to the left*/
midVal = PixelToTime(control, (left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + right) / 2);
SetSliderValue(slider, MAX(lo, value + midVal - testVal));
return ObjTrue;
}
testVal = PixelToTime(control, right - 1 - TCSCROLLBORDER);
if (value > testVal)
{
/*It's off to the right*/
midVal = PixelToTime(control, (left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + right) / 2);
SetSliderValue(slider, MIN(hi, value + midVal - testVal));
return ObjTrue;
}
return ObjFalse;
}
else
{
return ObjFalse;
}
}
static ObjPtr FindObjectTimeControl(object, name)
ObjPtr object;
char *name;
/*Searches a time control for an object with name*/
{
ObjPtr retVal = NULLOBJ;
ObjPtr objName;
ObjPtr scrollbar, textBox;
/*First check to see if I am the object*/
objName = GetVar(object, NAME);
if (objName && IsString(objName) && ObjectNameMatches(name, GetString(objName)))
{
if (!retVal)
{
retVal = NewList();
}
PostfixList(retVal, object);
}
/*Now check the scroll bars*/
scrollbar = GetVar(object, HSCROLL);
if (scrollbar)
{
objName = GetVar(scrollbar, NAME);
if (objName && IsString(objName) && 0 == strcmp2(GetString(objName), name))
{
if (!retVal)
{
retVal = NewList();
}
PostfixList(retVal, scrollbar);
}
}
scrollbar = GetVar(object, VSCROLL);
if (scrollbar)
{
objName = GetVar(scrollbar, NAME);
if (objName && IsString(objName) && 0 == strcmp2(GetString(objName), name))
{
if (!retVal)
{
retVal = NewList();
}
PostfixList(retVal, scrollbar);
}
}
textBox = GetVar(object, READOUT);
if (textBox)
{
objName = GetVar(textBox, NAME);
if (objName && IsString(objName) && 0 == strcmp2(GetString(objName), name))
{
if (!retVal)
{
retVal = NewList();
}
PostfixList(retVal, textBox);
}
}
return retVal;
}
static ObjPtr KeyDownTimeControl(object, key, flags)
ObjPtr object;
int key;
long flags;
/*Does a keydown in a time control*/
{
ObjPtr readout;
if (key == 0)
{
/*Do nothing with timeout*/
return ObjTrue;
}
if (AmICurrent(object) &&
(key == FK_LEFT_ARROW || key == FK_RIGHT_ARROW ||
key == FK_UP_ARROW || key == FK_DOWN_ARROW))
{
/*It's a keypress here*/
ObjPtr var;
ObjPtr timeSteps;
long index;
MakeVar(object, TIMESTEPS);
timeSteps = GetVar(object, TIMESTEPS);
if (!timeSteps)
{
return ObjTrue;
}
var = GetRealVar("KeyDownTimeControl", object, VALUE);
if (!var)
{
return ObjTrue;
}
index = SearchReal(timeSteps, GetReal(var));
if (key == FK_LEFT_ARROW || key == FK_DOWN_ARROW) index -= 2;
if (index < 0) index = DIMS(timeSteps)[0] - 1;
if (index >= DIMS(timeSteps)[0]) index = 0;
#ifdef INTERACTIVE
DrawInteractive(false);
#endif
SetVar(object, VALUE, NewReal(((real *) ELEMENTS(timeSteps))[index]));
UpdateTimeReadout(object);
if (logging)
{
LogControl(object);
}
AutoScroll(object);
ImInvalid(object);
ChangedValue(object);
}
readout = GetVar(object, READOUT);
if (readout || AmICurrent(readout))
{
return KeyDownObject(readout, key, flags);
}
else
{
return ObjFalse;
}
}
#ifdef INTERACTIVE
static ObjPtr PressTimeControl(object, x, y, flags)
ObjPtr object;
int x, y;
long flags;
/*Does a press in a time control beginning at x and y. Returns
true iff the press really was in the field.*/
{
int left, right, bottom, top;
ObjPtr scrollbar, textBox;
Get2DIntBounds(object, &left, &right, &bottom, &top);
/*See if it's a press in a scrollbar*/
scrollbar = GetVar(object, HSCROLL);
if (scrollbar)
{
if (IsTrue(PressObject(scrollbar, x, y, flags)))
{
return ObjTrue;
}
}
scrollbar = GetVar(object, VSCROLL);
if (scrollbar)
{
if (IsTrue(PressObject(scrollbar, x, y, flags)))
{
return ObjTrue;
}
}
/*Now the readout*/
textBox = GetVar(object, READOUT);
if (textBox)
{
if (IsTrue(PressObject(textBox, x, y, flags)))
{
return ObjTrue;
}
}
MakeMeCurrent(object);
if (x >= left && x <= right && y >= bottom && y <= top)
{
/*Hey! It really was a click in the time control*/
if (TOOL(flags) == T_HELP)
{
ContextHelp(object);
return ObjTrue;
}
if(GetVar(object, VALUE) &&
x >= left + TCDSWIDTH + 2 * TCGAP + BARWIDTH &&
x <= right &&
y >= top - TCTIMEHEIGHT - TCCURHEIGHT &&
y <= top - TCTIMEHEIGHT)
{
/*It's a click in the current time control*/
ObjPtr var;
real curTime, oldTime;
int timePixel;
int xOffset;
Bool inp; /*True iff in*/
int newX, newY; /*New x and y*/
ObjPtr timeSteps;
SaveForUndo(object);
/*If constrained, get the time steps*/
timeSteps = NULLOBJ;
if (flags & F_SHIFTDOWN)
{
MakeVar(object, TIMESTEPS);
timeSteps = GetVar(object, TIMESTEPS);
}
var = GetVar(object, VALUE);
if (var)
{
curTime = GetReal(var);
}
else
{
curTime = 0.0;
}
timePixel = TimeToPixel(object, curTime);
oldTime = curTime;
if (x >= timePixel - TCCURWIDTH / 2 && x <= timePixel + TCCURWIDTH / 2)
{
/*It's a click on the thumb. Set offset*/
xOffset = timePixel - x;
}
else
{
/*No offset*/
xOffset = 0;
}
/*Start off inside*/
inp = true;
SetVar(object, HIGHLIGHTED, ObjTrue);
/*Make current x and y bogus*/
x = -12345; y = -12345;
while (Mouse(&newX, &newY))
{
if (newX != x)
{
x = newX;
y = newY;
/*Check to see if it's outside*/
if (y < top - TCTIMEHEIGHT - TCCURHEIGHT - SLOP ||
y > top - TCTIMEHEIGHT + SLOP)
{
/*Yes, it's outside*/
if (inp)
{
/*Transition from in to out*/
SetVar(object, VALUE, NewReal(oldTime));
UpdateTimeReadout(object);
SetVar(object, HIGHLIGHTED, ObjFalse);
inp = false;
#ifdef SCROLLTIME
if (AutoScroll(object))
{
x = -12345;
}
#endif
DrawMe(object);
}
}
else
{
/*No, it's inside*/
if (!inp)
{
/*Transition from out to in*/
inp = true;
SetVar(object, HIGHLIGHTED, ObjTrue);
}
curTime = PixelToTime(object, x + xOffset);
if (timeSteps)
{
/*Constrain the time to the closest time step*/
long index; /*Index into timesteps*/
real *timeElements; /*Elements of the timesteps*/
timeElements = ELEMENTS(timeSteps);
index = SearchReal(timeSteps, curTime);
if (index <= 0)
{
curTime = timeElements[0];
}
else if (index >= DIMS(timeSteps)[0])
{
curTime = timeElements[DIMS(timeSteps)[0] - 1];
}
else if (timeElements[index] - curTime >
curTime - timeElements[index - 1])
{
curTime = timeElements[index - 1];
}
else
{
curTime = timeElements[index];
}
}
SetVar(object, VALUE, NewReal(curTime));
UpdateTimeReadout(object);
#ifdef SCROLLTIME
if (AutoScroll(object))
{
x = -12345;
}
#endif
DrawMe(object);
}
}
}
if (inp)
{
SetVar(object, HIGHLIGHTED, ObjFalse);
if (logging)
{
LogControl(object);
}
ChangedValue(object);
}
}
#if 0
int xOff, yOff;
GETSCROLL(object, xOff, yOff);
SetClipRect(left + FIELDDEPTH, right - FIELDDEPTH, bottom + FIELDDEPTH, top - FIELDDEPTH);
SetOrigin(left + FIELDDEPTH + xOff, bottom + FIELDDEPTH + yOff);
x -= left + FIELDDEPTH + xOff;
y -= bottom + FIELDDEPTH + yOff;
pressContents = GetMethod(object, PRESSCONTENTS);
if (pressContents)
{
(*pressContents)(object, x, y, flags);
}
RestoreOrigin();
RestoreClipRect();
#endif
return ObjTrue;
}
else
{
return ObjFalse;
}
}
#endif
static ObjPtr ChangeTimeControlScroll(scrollbar)
ObjPtr scrollbar;
/*Changes the time control scrollbar*/
{
ObjPtr repObj;
repObj = GetVar(scrollbar, REPOBJ);
if (repObj)
{
ImInvalid(repObj);
}
return ObjTrue;
}
static ObjPtr MakeTimeControlDatasets(control)
ObjPtr control;
/*Makes the time control's DATASETS*/
{
SetVar(control, DATASETS, GetVar(GetVar(control, REPOBJ), DATASETS));
RecalcScroll(control);
return ObjTrue;
}
static ObjPtr MakeTimeControlTimesteps(control)
ObjPtr control;
/*Makes the time control's timesteps*/
{
ObjPtr datasets;
ObjPtr element;
ObjPtr steps = NULLOBJ;
long k;
MakeVar(control, DATASETS);
datasets = GetVar(control, DATASETS);
if (datasets)
{
for (k = 0; k < DIMS(datasets)[0]; ++k)
{
ObjPtr curTimeSteps;
element = GetObjectElement(datasets, &k);
MakeVar(element, TIMESTEPS);
curTimeSteps = GetVar(element, TIMESTEPS);
if (curTimeSteps)
{
if (steps)
{
steps = MergeRealArrays(steps, curTimeSteps);
}
else
{
steps = curTimeSteps;
}
}
}
}
SetVar(control, TIMESTEPS, steps);
return ObjTrue;
}
static ObjPtr MakeTimeControlFormat(control)
ObjPtr control;
/*Makes the time control's TIMEFORMAT*/
{
ObjPtr repObj;
repObj = GetObjectVar("MakeTimeControlFormat", control, REPOBJ);
if (repObj)
{
MakeVar(repObj, TIMEFORMAT);
SetVar(control, TIMEFORMAT, GetVar(repObj, TIMEFORMAT));
RecalcScroll(control);
}
}
static ObjPtr RecalcTimeControlScroll(control)
ObjPtr control;
/*Recalcs the time control scrolling and other parameters*/
{
real value;
ObjPtr var, scrollbar, repObj, readout;
int left, right, bottom, top;
ObjPtr datasets;
int format;
Get2DIntBounds(control, &left, &right, &bottom, &top);
repObj = GetVar(control, REPOBJ);
MakeVar(control, DATASETS);
datasets = GetVar(control, DATASETS);
MakeVar(control, TIMEFORMAT);
var = GetVar(control, TIMEFORMAT);
if (var)
{
format = GetInt(var);
}
else
{
format = TF_SECONDS + TF_SUBSECONDS;
}
readout = GetObjectVar("RecalcTimeControlScroll", control, READOUT);
if (!readout)
{
return false;
}
/*Set the horizontal scroll bar*/
scrollbar = GetVar(control, HSCROLL);
if (scrollbar)
{
ObjPtr timeSteps;
real lo, hi, minTimeStep;
Bool stepSet = false;
Bool loHiSet = false;
Bool someTime = false;
/*Calculate timeSteps*/
if (datasets)
{
ObjPtr element;
long k;
for (k = 0; k < DIMS(datasets)[0]; ++k)
{
ObjPtr timeSteps;
element = GetObjectElement(datasets, &k);
MakeVar(element, TIMESTEPS);
timeSteps = GetVar(element, TIMESTEPS);
if (timeSteps)
{
ObjPtr deltas;
deltas = SortArray(Uniq(RealArrayDeltas(timeSteps)));
someTime = true;
/*Set the lo and hi*/
if (loHiSet)
{
lo = MIN(lo,
*((real *) ELEMENTS(timeSteps)));
hi = MAX(hi,
((real *) ELEMENTS(timeSteps))[DIMS(timeSteps)[0] - 1]);
}
else
{
lo = *((real *) ELEMENTS(timeSteps));
hi = ((real *) ELEMENTS(timeSteps))[DIMS(timeSteps)[0] - 1];
loHiSet = true;
}
/*Set the step only if there is one*/
if (DIMS(timeSteps)[0] > 1)
{
if (stepSet)
{
minTimeStep = MIN(minTimeStep,
*((real *) ELEMENTS(deltas)));
}
else
{
minTimeStep = *((real *) ELEMENTS(deltas));
stepSet = true;
}
}
}
}
}
if (someTime)
{
ActivateTextBox(readout, true);
}
else
{
ActivateTextBox(readout, false);
/*Kludge to make time go away*/
SetVar(control, VALUE, NULLOBJ);
SetVar(control, VALUESET, ObjFalse);
SetVar(repObj, TIME, NULLOBJ);
UpdateTimeReadout(control);
}
if (loHiSet)
{
/*Deal with existing value*/
var = GetVar(control, VALUE);
if (var)
{
if (!GetPredicate(control, VALUESET))
{
/*It hasn't been set yet*/
SetVar(control, VALUESET, ObjTrue);
SetSliderValue(scrollbar, GetReal(var));
}
#if 0
/*There already is a value. Extend lo and hi*/
value = GetReal(var);
lo = MIN(lo, value);
hi = MAX(hi, value);
#endif
}
else
{
/*There's a new value*/
value = lo;
SetValue(control, NewReal(value));
SetSliderValue(scrollbar, value);
}
SetSliderRange(scrollbar, hi, lo, minTimeStep);
}
else
{
SetSliderValue(scrollbar, 0.0);
SetSliderRange(scrollbar, 0.0, 1.0, 20.0);
}
if (stepSet)
{
double deltaLog;
int nTics;
real timePerPixel, timeShown, trialDisplay;
/*There is more than one time sample. Calculate time per pixel
and scrollbar coverage*/
timePerPixel = minTimeStep / TCSTEPPIXELS;
SetVar(control, TIMEPERPIXEL, NewReal(timePerPixel));
timeShown = (right - 1 - (left + TCDSWIDTH + 2 * TCGAP + BARWIDTH + 1))
* timePerPixel;
SetPortionShown(scrollbar, timeShown);
/*Also calculate DISPLAYSTEP*/
if ((format & TF_HOURS) || (format & TF_MINUTES))
{
/*It's HMS*/
if (minTimeStep < 10.0)
{
/*Might as well ignore hours and minutes*/
deltaLog = floor(log((double) minTimeStep) / LOGE10);
trialDisplay = pow((double) 10.0, deltaLog);
nTics = 10;
}
else
{
deltaLog = floor(log((double) minTimeStep) / LOGE10);
trialDisplay = pow((double) 60.0, deltaLog);
nTics = 10;
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 5*/
trialDisplay *= 5.0;
nTics = 5;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 15*/
trialDisplay *= 3.0;
nTics = 3;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 30*/
trialDisplay *= 2.0;
nTics = 2;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 60*/
trialDisplay *= 2.0;
nTics = 4;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 5*/
trialDisplay *= 5.0;
nTics = 5;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 15*/
trialDisplay *= 3.0;
nTics = 3;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 30*/
trialDisplay *= 2.0;
nTics = 2;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 60*/
trialDisplay *= 2.0;
nTics = 4;
}
}
}
else
{
deltaLog = floor(log((double) minTimeStep) / LOGE10);
trialDisplay = pow((double) 10.0, deltaLog);
nTics = 10;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 2*/
trialDisplay *= 2.0;
nTics = 2;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 5*/
trialDisplay *= 2.5;
nTics = 5;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 10*/
trialDisplay *= 2.0;
nTics = 10;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 2*/
trialDisplay *= 2.0;
nTics = 2;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 5*/
trialDisplay *= 2.5;
nTics = 5;
}
if (trialDisplay / timePerPixel < TCTIMEPIXELS)
{
/*Try 10*/
trialDisplay *= 2.0;
nTics = 10;
}
SetVar(control, DISPLAYSTEP, NewReal(trialDisplay));
SetVar(control, DISPLAYTICS, NewInt(nTics));
}
else
{
/*No more than one time sample, no need to have any time per pixel*/
SetVar(control, TIMEPERPIXEL, NULLOBJ);
SetPortionShown(scrollbar, 1.0);
}
}
/*Set the vertical scroll bar*/
scrollbar = GetVar(control, VSCROLL);
if (scrollbar)
{
if (datasets)
{
long dsSize, boxSize, height;
dsSize = TCCELLHEIGHT * DIMS(datasets)[0];
boxSize = top - TCCURHEIGHT - TCTIMEHEIGHT - TCGAP - 1 - (bottom + TCGAP + BARWIDTH + 1);
if (dsSize < boxSize)
{
height = 0;
dsSize = 1;
}
else
{
height = dsSize - boxSize;
}
SetSliderRange(scrollbar, 0.0, (real) -height, TCCELLHEIGHT);
SetPortionShown(scrollbar, (real) dsSize);
}
else
{
SetSliderRange(scrollbar, 0.0, -1.0, 20.0);
SetPortionShown(scrollbar, 1.0);
}
}
return ObjTrue;
}
static ObjPtr SetTimeControlValue(control, value)
ObjPtr control;
ObjPtr value;
/*Sets the value of a time control*/
{
if (IsReal(value))
{
SetVar(control, VALUE, value);
}
else if (IsInt(value))
{
SetVar(control, VALUE, NewReal(GetInt(value)));
}
else
{
return ObjFalse;
}
UpdateTimeReadout(control);
if (logging)
{
LogControl(control);
}
ImInvalid(control);
ChangedValue(control);
return ObjTrue;
}
static ObjPtr ChangeTimeReadout(readout)
ObjPtr readout;
/*CHANGEDVALUE for a time control readout*/
{
ObjPtr value;
char *s;
real t;
int f;
int position;
ObjPtr parent;
value = GetValue(readout);
if (!value)
{
return ObjFalse;
}
s = GetString(value);
parent = GetVar(readout, PARENT);
if (!parent)
{
return ObjFalse;
}
position = ParseTime(&t, &f, s);
if (position > 0)
{
FuncTyp method;
/*It's OK*/
method = GetMethod(readout, CHANGEDVALUE);
SetMethod(readout, CHANGEDVALUE, 0);
InhibitLogging(true);
SetValue(parent, NewReal(t));
AutoScroll(parent);
InhibitLogging(false);
SetMethod(readout, CHANGEDVALUE, method);
}
else
{
WarnUser(CW_NUMBERERROR);
return ObjFalse;
}
return ObjTrue;
}
ObjPtr TimeControlBoundsInvalid(object, changeCount)
ObjPtr object;
unsigned long changeCount;
/*For a time control, tests to see if it needs drawing. Returns
NULLOBJ if it does not
array[4] giving bounds if it does
ObjTrue it it needs to be redrawn but does not know where
*/
{
ObjPtr datasets;
ObjPtr myBounds;
real boundsElements[4];
real testElements[4];
ObjPtr test;
real myBoundsElements[4];
ObjPtr scrollBar, readout;
Bool firstTime = true;
Bool doubleNoBounds = false;
MakeVar(object, APPEARANCE);
MakeVar(object, CHANGEDBOUNDS);
if (GetVarChangeCount(object, CHANGEDBOUNDS) > changeCount)
{
/*Object is not good, so return the bounds*/
myBounds = GetVar(object, CHANGEDBOUNDS);
if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
&& DIMS(myBounds)[0] == 4)
{
return myBounds;
}
else
{
return ObjTrue;
}
}
MakeVar(object, BOUNDS);
myBounds = GetVar(object, BOUNDS);
Array2CArray(myBoundsElements, myBounds);
scrollBar = GetVar(object, HSCROLL);
if (scrollBar);
{
test = BoundsInvalid(scrollBar, changeCount);
if (test)
{
/*Hey, the scroll bar needs redrawing*/
if (IsRealArray(test))
{
/*It has a bounds*/
if (firstTime)
{
Array2CArray(boundsElements, test);
}
else
{
Array2CArray(testElements, test);
if (testElements[0] < boundsElements[0])
boundsElements[0] = testElements[0];
if (testElements[1] > boundsElements[1])
boundsElements[1] = testElements[1];
if (testElements[2] < boundsElements[2])
boundsElements[2] = testElements[2];
if (testElements[3] > boundsElements[3])
boundsElements[3] = testElements[3];
}
}
else
{
/*It doesn't have a bounds*/
if (firstTime)
{
/*Try to use my bounds*/
if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
&& DIMS(myBounds)[0] == 4)
{
Array2CArray(boundsElements, myBounds);
}
else
{
doubleNoBounds = true;
}
}
}
firstTime = false;
}
}
scrollBar = GetVar(object, VSCROLL);
if (scrollBar);
{
test = BoundsInvalid(scrollBar, changeCount);
if (test)
{
/*Hey, the scroll bar needs redrawing*/
if (IsRealArray(test))
{
/*It has a bounds*/
if (firstTime)
{
Array2CArray(boundsElements, test);
}
else
{
Array2CArray(testElements, test);
if (testElements[0] < boundsElements[0])
boundsElements[0] = testElements[0];
if (testElements[1] > boundsElements[1])
boundsElements[1] = testElements[1];
if (testElements[2] < boundsElements[2])
boundsElements[2] = testElements[2];
if (testElements[3] > boundsElements[3])
boundsElements[3] = testElements[3];
}
}
else
{
/*It doesn't have a bounds*/
if (firstTime)
{
/*Try to use my bounds*/
if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
&& DIMS(myBounds)[0] == 4)
{
Array2CArray(boundsElements, myBounds);
}
else
{
doubleNoBounds = true;
}
}
}
firstTime = false;
}
}
readout = GetVar(object, READOUT);
if (readout);
{
test = BoundsInvalid(readout, changeCount);
if (test)
{
/*Hey, the scroll bar needs redrawing*/
if (IsRealArray(test))
{
/*It has a bounds*/
if (firstTime)
{
Array2CArray(boundsElements, test);
}
else
{
Array2CArray(testElements, test);
if (testElements[0] < boundsElements[0])
boundsElements[0] = testElements[0];
if (testElements[1] > boundsElements[1])
boundsElements[1] = testElements[1];
if (testElements[2] < boundsElements[2])
boundsElements[2] = testElements[2];
if (testElements[3] > boundsElements[3])
boundsElements[3] = testElements[3];
}
}
else
{
/*It doesn't have a bounds*/
if (firstTime)
{
/*Try to use my bounds*/
if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
&& DIMS(myBounds)[0] == 4)
{
Array2CArray(boundsElements, myBounds);
}
else
{
doubleNoBounds = true;
}
}
}
firstTime = false;
}
}
/*See if we need to change the bounds based on changed datasets*/
MakeVar(object, DATASETS);
datasets = GetVar(object, DATASETS);
if (datasets && IsList(datasets))
{
/*Go through the datasets*/
ThingListPtr runner;
runner = LISTOF(datasets);
while (runner)
{
if (GetVarChangeCount(runner -> thing, CHANGED) > changeCount)
{
boundsElements[0] = myBoundsElements[0];
boundsElements[1] = myBoundsElements[1];
boundsElements[2] = myBoundsElements[2];
boundsElements[3] = myBoundsElements[3];
firstTime = false;
}
MakeVar(runner -> thing, INTERPOLATEP);
if (GetVarChangeCount(runner -> thing, INTERPOLATEP) > changeCount)
{
boundsElements[0] = myBoundsElements[0];
boundsElements[1] = myBoundsElements[1];
boundsElements[2] = myBoundsElements[2];
boundsElements[3] = myBoundsElements[3];
firstTime = false;
}
runner = runner -> next;
}
}
/*Now return the bounds*/
if (firstTime != true)
{
if (doubleNoBounds)
{
return ObjTrue;
}
else
{
ObjPtr retVal;
retVal = NewRealArray(1, 4L);
CArray2Array(retVal, boundsElements);
return retVal;
}
}
return NULLOBJ;
}
ObjPtr NewTimeControl(l, r, b, t, name)
int l, r, b, t;
char *name;
/*Makes a new time control within l, r, b, t with name name*/
{
ObjPtr retVal, scrollbar, readout;
retVal = NewObject(timeControlClass, 0);
if (!retVal)
{
return NULLOBJ;
}
Set2DIntBounds(retVal, l, r, b, t);
SetVar(retVal, NAME, NewString(name));
/*Create the scroll bars*/
scrollbar = NewScrollbar(l + TCDSWIDTH + TCGAP, l + TCDSWIDTH + TCGAP + BARWIDTH,
b + BARWIDTH + TCGAP,
t - TCTIMEHEIGHT - TCCURHEIGHT - TCGAP,
"Dataset Scroll");
SetVar(scrollbar, PARENT, retVal);
SetVar(scrollbar, REPOBJ, retVal);
SetMethod(scrollbar, CHANGEDVALUE, ChangeTimeControlScroll);
SetVar(retVal, VSCROLL, scrollbar);
scrollbar = NewScrollbar(l + TCDSWIDTH + 2 * TCGAP + BARWIDTH, r,
b,
b + BARWIDTH,
"Time Scroll");
SetVar(scrollbar, PARENT, retVal);
SetVar(scrollbar, REPOBJ, retVal);
SetMethod(scrollbar, CHANGEDVALUE, ChangeTimeControlScroll);
SetVar(retVal, HSCROLL, scrollbar);
/*Create the readout*/
readout = NewTextBox(l, l + TCDSWIDTH + TCGAP + BARWIDTH,
t - TCTIMEHEIGHT - TCCURHEIGHT, t - TCTIMEHEIGHT,
EDITABLE + WITH_PIT + ONE_LINE, "Time Readout", "0.0");
SetMethod(readout, CHANGEDVALUE, ChangeTimeReadout);
SetVar(readout, PARENT, retVal);
SetTextAlign(readout, RIGHTALIGN);
SetVar(retVal, READOUT, readout);
return retVal;
}
void InitTimers()
/*Initializes the timers system*/
{
int k;
struct tms buffer;
startTime = times(&buffer);
timedObjClass = NewObject(NULLOBJ, 0);
SetVar(timedObjClass, CLASSID, NewInt(CLASS_TIMEDOBJ));
DeclareDependency(timedObjClass, TIMEBOUNDS, TIMESTEPS);
DeclareDependency(timedObjClass, TIMEBOUNDS, TIMEDATA);
SetMethod(timedObjClass, TIMEBOUNDS, MakeTimeBounds);
SetMethod(timedObjClass, REGISTERFIELD, RegisterTimedField);
AddToReferenceList(timedObjClass);
timeControlClass = NewObject(controlClass, 0);
SetMethod(timeControlClass, DRAW, DrawTimeControl);
SetMethod(timeControlClass, FINDOBJECT, FindObjectTimeControl);
#ifdef INTERACTIVE
SetMethod(timeControlClass, PRESS, PressTimeControl);
#endif
SetMethod(timeControlClass, BOUNDSINVALID, TimeControlBoundsInvalid);
SetMethod(timeControlClass, KEYDOWN, KeyDownTimeControl);
SetMethod(timeControlClass, RECALCSCROLL, RecalcTimeControlScroll);
SetMethod(timeControlClass, SETVAL, SetTimeControlValue);
SetMethod(timeControlClass, AUTOSCROLL, AutoScrollTimeControl);
SetVar(timeControlClass, TYPESTRING, NewString("time control"));
SetVar(timeControlClass, HELPSTRING,
NewString("This control shows the current time in a clock. On the \
left is a box containing the names all the datasets in all the visualization objects that this \
clock controls. On the right is the time line of each dataset, lined up with \
the dataset name. A horizontal blue line means that the dataset is eternal and \
is defined for all time. Blue diamonds indicate time steps in time-dependent \
data. Between the diamonds, dashed black lines indicate that the nearest \
timestep to the current time will be displayed. Solid black lines indicate that the data will be \
interpolated between time steps. You can change whether a dataset will be \
interpolated using the Show Info button \
in the Datasets window.\n\
\n\
At the top left is a text box that shows the current time. At the top right is \
a slider connected to a cursor that shows the current time as well as its relation \
to the datasets controlled by the clock. You can change the current time either by \
editing the text or moving the indicator. Hold down the Shift key while moving \
the indicator to constrain to actual time steps. If none of the datasets are time-dependent, \
both of these will show as gray."));
DeclareIndirectDependency(timeControlClass, DATASETS, REPOBJ, DATASETS);
SetMethod(timeControlClass, DATASETS, MakeTimeControlDatasets);
DeclareIndirectDependency(timeControlClass, TIMEFORMAT, REPOBJ, TIMEFORMAT);
SetMethod(timeControlClass, TIMEFORMAT, MakeTimeControlFormat);
DeclareDependency(timeControlClass, TIMESTEPS, DATASETS);
SetMethod(timeControlClass, TIMESTEPS, MakeTimeControlTimesteps);
AddToReferenceList(timeControlClass);
for (k = 0; k < NALARMS; ++k)
{
alarms[k] . object = 0;
}
}
void KillTimers()
/*Kills the timers system*/
{
int k;
DeleteThing(timeControlClass);
DeleteThing(timedObjClass);
for (k = 0; k < NALARMS; ++k)
{
if (alarms[k] . object)
{
ObjPtr object;
object = alarms[k] . object;
alarms[k] . object = 0;
DeleteThing(object);
}
}
}